package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"path"
	"time"
)

func main() {

	engine := gin.Default()

	engine.LoadHTMLGlob("./templates/**")

	engine.GET("/ping", func(ctx *gin.Context) {
		ctx.JSON(200, gin.H{
			"message": "pong",
		})
	})

	engine.GET("/template", func(ctx *gin.Context) {
		ctx.HTML(http.StatusOK, "hello.tmpl", gin.H{
			"title": "go hello world",
		})
	})

	engine.GET("/json", func(ctx *gin.Context) {
		//data := map[string]interface{}{
		//	"name":    "进击的巨人",
		//	"age":     25,
		//	"message": "建议25岁以上观看",
		//}

		//data := gin.H{
		//	"name":    "进击的巨人",
		//	"age":     25,
		//	"message": "建议25岁以上观看",
		//}

		type Payload struct {
			Name string `json:"name"`
			Age  uint16 `json:"age"`
			Msg  string `json:"message"`
		}

		data := Payload{
			Name: "进击的巨人",
			Age:  25,
			Msg:  "建议25岁以上观看",
		}

		ctx.JSON(http.StatusOK, data)
	})

	engine.GET("/querystring", func(ctx *gin.Context) {

		q := ctx.Query("q")

		q = ctx.DefaultQuery("q", "nil")

		q, ok := ctx.GetQuery("q")
		if !ok {
			q = "nil"
		}

		ctx.JSON(http.StatusOK, gin.H{
			"query": q,
		})
	})

	engine.GET("login", func(ctx *gin.Context) {

		ctx.HTML(http.StatusOK, "login.tmpl", nil)

	})

	// 获取 form 表单参数
	engine.POST("/auth", func(ctx *gin.Context) {

		username := ctx.DefaultPostForm("username", "")
		pwd := ctx.DefaultPostForm("pwd", "")

		ctx.JSON(http.StatusOK, gin.H{
			"username": username,
			"pwd":      pwd,
			"msg":      "Ok",
		})

	})

	// 获取 path 参数
	engine.GET("/:arg1/:arg2", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"arg1": ctx.Param("arg1"),
			"arg2": ctx.Param("arg2"),
			"msg":  "Ok",
		})
	})

	engine.GET("/blog/:year/:month", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"year":  ctx.Param("year"),
			"month": ctx.Param("month"),
			"msg":   "Ok",
		})
	})

	// 参数绑定
	type UserInfo struct {
		Username string `json:"username"  form:username`
		Age      uint16 `json:"age" from:age`
	}

	engine.POST("/user-json", func(ctx *gin.Context) {
		var u UserInfo
		err := ctx.ShouldBind(&u)
		if err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{
				"err": err.Error(),
			})
			return
		}

		ctx.JSON(http.StatusOK, gin.H{
			"payload": u,
			"msg":     "OK",
		})
	})

	engine.POST("/user-form", func(ctx *gin.Context) {
		var u UserInfo
		err := ctx.ShouldBind(&u)
		if err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{
				"err": err.Error(),
			})
			return
		}

		ctx.JSON(http.StatusOK, gin.H{
			"payload": u,
			"msg":     "OK",
		})
	})

	// 上传文件
	engine.GET("/upload-page", func(ctx *gin.Context) {

		ctx.HTML(http.StatusOK, "upload.tmpl", nil)

	})

	engine.POST("/upload", func(ctx *gin.Context) {
		file, err := ctx.FormFile("file")

		if err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{
				"err": err.Error(),
			})
			return
		}

		dst := path.Join("./", file.Filename)
		err = ctx.SaveUploadedFile(file, dst)
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"err": err.Error(),
			})
			return
		}

		ctx.JSON(http.StatusOK, gin.H{
			"msg": "Ok",
		})
	})

	// 请求重定向
	engine.GET("redirect-1", func(ctx *gin.Context) {

		ctx.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
	})

	// 路由重定向,转发
	engine.GET("redirect-2", func(ctx *gin.Context) {

		ctx.Request.URL.Path = "/ping"
		engine.HandleContext(ctx)
	})

	// gin 路由
	engine.GET("/index", func(ctx *gin.Context) {

		ctx.JSON(http.StatusOK, gin.H{
			"method": "get",
		})

	})

	engine.POST("/index", func(ctx *gin.Context) {

		ctx.JSON(http.StatusOK, gin.H{
			"method": "post",
		})

	})

	engine.PUT("/index", func(ctx *gin.Context) {

		ctx.JSON(http.StatusOK, gin.H{
			"method": "put",
		})

	})

	engine.DELETE("/index", func(ctx *gin.Context) {

		ctx.JSON(http.StatusOK, gin.H{
			"method": "delete",
		})

	})

	engine.Any("/index-any", func(ctx *gin.Context) {

		ctx.JSON(http.StatusOK, gin.H{
			"method": ctx.Request.Method,
		})

	})

	engine.NoRoute(func(ctx *gin.Context) {

		ctx.HTML(http.StatusNotFound, "404.tmpl", nil)
	})

	// 路由组 ， 可嵌套
	// 路由组也可以注册中间件
	vg := engine.Group("/video").Use(Cost())

	{
		vg.GET("/", func(ctx *gin.Context) {
			ctx.JSON(http.StatusOK, gin.H{
				"msg": "video get",
			})
		})

		vg.POST("/", func(ctx *gin.Context) {
			ctx.JSON(http.StatusOK, gin.H{
				"msg": "video post",
			})
		})

		vg.PUT("/", func(ctx *gin.Context) {
			ctx.JSON(http.StatusOK, gin.H{
				"msg": "video put",
			})
		})

		vg.DELETE("/", func(ctx *gin.Context) {
			ctx.JSON(http.StatusOK, gin.H{
				"msg": "video delete",
			})
		})
	}

	// 中间件
	engine.Any("/middleware-1", func(ctx *gin.Context) {
		fmt.Println("exe ................")
		start := time.Now()
		// 调用下一个 handler func
		ctx.Next()

		// 阻止调用下一个 HandlerFunc
		//ctx.Abort()
		cost := time.Since(start)
		fmt.Printf("cost:%v\n", cost)

	}, func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"msg": "Ok",
		})
	})

	// 全局注册中间件函数
	engine.Use(Cost())

	engine.Any("/middleware-2", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"msg": "Ok",
		})
	})

	_ = engine.Run()
}

func Cost() gin.HandlerFunc {

	return func(ctx *gin.Context) {

		fmt.Println("Cost func exe ................")
		start := time.Now()
		// 调用下一个 handler func
		ctx.Next()

		// 阻止调用下一个 HandlerFunc
		//ctx.Abort()
		cost := time.Since(start)
		fmt.Printf("cost:%v\n", cost)

	}
}
